module ActsAsTaggableOnPadrino
  class Tag < ::ActiveRecord::Base
    attr_accessible :name

    ### ASSOCIATIONS:

    has_many :taggings, :dependent => :destroy, :class_name => 'ActsAsTaggableOnPadrino::Tagging'

    ### VALIDATIONS:
    validates_presence_of :name
    validates_uniqueness_of :name

    ### SCOPES:
    # Override this with 'ILIKE' for case-insensitive operation on postgres
    cattr_accessor :like_operator
    self.like_operator = 'LIKE'

    scope :named, lambda {|name| where(["name #{like_operator} ?", name]) }
    scope :named_any, lambda {|list| where(list.map { |tag| sanitize_sql(["name #{like_operator} ?", tag.to_s]) }.join(" OR ")) }
    scope :named_like, lambda {|name| where(["name #{like_operator} ?", "%#{name}%"]) }
    scope :named_like_any, lambda {|list| where(list.map { |tag| sanitize_sql(["name #{like_operator} ?", "%#{tag.to_s}%"]) }.join(" OR ")) }

    ### CLASS METHODS:

    class << self
      def using_postgresql?
        connection.adapter_name == 'PostgreSQL'
      end

      def find_or_create_with_like_by_name(name)
        named_like(name).first || create(:name => name)
      end

      def find_or_create_all_with_like_by_name(*list)
        list = list.flatten
        return [] if list.empty?

        existing_tags = Tag.named_any(list)
        new_tag_names = list.reject do |name|
                          name = comparable_name(name)
                          existing_tags.any? { |tag| comparable_name(tag.name) == name }
                        end
        created_tags  = new_tag_names.map { |name| Tag.create(:name => name) }

        existing_tags + created_tags
      end

      def names
        all.map {|tag| tag.name }
      end

    private
      def comparable_name(str)
        RUBY_VERSION >= "1.9" ? str.downcase : str.mb_chars.downcase
      end
    end

    ### INSTANCE METHODS:

    def ==(object)
      super || (object.is_a?(Tag) && name == object.name)
    end

    def to_s
      name
    end

    def count
      read_attribute(:count).to_i
    end
  end
end